#include "scilp.h"

log_default_streams_t ilpl;
static glob_t seq_glob;
static int seq_nr=0;
long unsigned int seed=1;

void scIlpInit(int proc)
{
  glob(SCCILP_SEQUENCE_INPUT, 0, NULL, &seq_glob);
  lprintf(STREAM(ilpl.debug), "Capture from a sequence of %d elements", seq_glob.gl_pathc);
}

#define SCC_IMWIDTH     (1024)
#define SCC_WIDTH       (1024)
#define SCC_HEIGHT      (1024)
#define SCC_OPBYTES     (SCC_WIDTH*SCC_HEIGHT)

void ilpOperationEnqueue(ilp_op_t *op)
{
  char namebuf[PATH_MAX];
  unsigned char buf[SCC_WIDTH];
  FILE *f;
  size_t bytes, lines;
  scu_bufptrid_t r;

  switch (op->operation)
  {
    case READ:
      /* Read */
      sprintf(namebuf, SCCILP_IMAGE_INPUT, op->argument[0].data.d);
      lprintf(STREAM(ilpl.notice), "Reading, file='%s' (dI)", namebuf);
      abortOnNULL(STREAM(ilpl.err), f = fopen(namebuf, "r"));
      while ((bytes=fread(buf, 1, SCC_WIDTH, f)) > 0)
	scuBufferWrite(op->argument[1].buffer, buf, bytes,
		       SCU_BUF_BLOCK_ALL);
      scuBufferFinalize(op->argument[1].buffer);
      fclose(f);
      break;
    case WRITE:
      /* Write */
      r = op->argument[0].reader;
      sprintf(namebuf, SCCILP_IMAGE_OUTPUT, op->argument[1].data.d);
      lprintf(STREAM(ilpl.notice), "Writing, file='%s' (id)", namebuf);
      abortOnNULL(STREAM(ilpl.err), f = fopen(namebuf, "w"));
      while (!scuBufferIsDry(op->argument[0].buffer, r))
      {
	bytes = scuBufferRead(op->argument[0].buffer, r,
			      buf, SCC_WIDTH, SCU_BUF_BLOCK_ANY);
	fwrite(buf, 1, bytes, f);
      }
      scuBufferRemoveReference(op->argument[0].buffer);
      fclose(f);

      break;
    case GENERATE:
      /* Generate */
      lprintf(STREAM(ilpl.notice), "Generating (d=%d,I)",
	      op->argument[0].data.d);
	      
      for (lines=0; lines < op->argument[0].data.d; lines++)
      {
	char *buf;
	int i;

	scuBufferAllocate(op->argument[1].buffer, (void**) &buf, SCC_WIDTH,
			  SCU_BUF_BLOCK_ALL);

	for (i=0; i < SCC_WIDTH; i++)
	{
          long unsigned int hi, lo;

	  buf[i] = seed;

#define constapmc 16807                                    

          /* http://www.firstpr.com.au/dsp/rand31/ */
          lo = constapmc * (seed & 0xFFFF);
          hi = constapmc * (seed >> 16);
          lo += (hi & 0x7FFF) << 16;
          lo += hi >> 15;                  
          if (lo > 0x7FFFFFFF) lo -= 0x7FFFFFFF;          
        
          seed = (long)lo;
	}

	scuBufferReleaseAllocated(op->argument[1].buffer, SCC_WIDTH);
      }
      scuBufferFinalize(op->argument[1].buffer);
      break;
    case DISCARD:
    case DISPLAY:
      /* Discard */
      r = op->argument[0].reader;
      lprintf(STREAM(ilpl.notice), "Discarding (i)");
      while (!scuBufferIsDry(op->argument[0].buffer, r))
      {
	char *buf;

	bytes = scuBufferPeek(op->argument[0].buffer, r,
			      (void**) &buf, SCC_WIDTH, SCU_BUF_BLOCK_ANY);
	scuBufferReleasePeeked(op->argument[0].buffer, r, bytes);
      }
      scuBufferRemoveReference(op->argument[0].buffer);

      break;
    case CAPTURE:
      /* Read */
      strcpy(namebuf, seq_glob.gl_pathv[seq_nr]);

      lprintf(STREAM(ilpl.notice), "Capturing, file='%s' (I)", namebuf);

      seq_nr++;
      if (seq_nr >= seq_glob.gl_pathc)
	seq_nr = 0;

      abortOnNULL(STREAM(ilpl.err), f = fopen(namebuf, "r"));
      while ((bytes=fread(buf, 1, SCC_WIDTH, f)) > 0)
	scuBufferWrite(op->argument[0].buffer, buf, bytes,
		       SCU_BUF_BLOCK_ALL);
      scuBufferFinalize(op->argument[0].buffer);
      fclose(f);
      break;      
    case LOAD:
      /* Read */
      fprintf(stderr, "Load operation unsupported\n");
      break;
    case CYCLE:
      lprintf(STREAM(ilpl.notice), "Cycling (iI)");
      r = op->argument[0].reader;
      while (!scuBufferIsDry(op->argument[0].buffer, r))
      {
	bytes = scuBufferRead(op->argument[0].buffer, r,
			      buf, SCC_WIDTH, SCU_BUF_BLOCK_ANY);
	scuBufferWrite(op->argument[1].buffer, buf, bytes,
		       SCU_BUF_BLOCK_ALL);
      }
      scuBufferRemoveReference(op->argument[0].buffer);
      scuBufferFinalize(op->argument[1].buffer);
      break;
    case GENSIZE:
      lprintf(STREAM(ilpl.notice), "Generating from input size (iI)");
      r = op->argument[0].reader;
      while (!scuBufferIsDry(op->argument[0].buffer, r))
      {
	bytes = scuBufferPeek(op->argument[0].buffer, r,
			      (void**)&buf, SCC_WIDTH, SCU_BUF_BLOCK_ANY);
	scuBufferReleasePeeked(op->argument[0].buffer, r, bytes);
	scuBufferAllocate(op->argument[1].buffer, (void**)&buf, bytes,
	                  SCU_BUF_BLOCK_ALL);
        scuBufferReleaseAllocated(op->argument[1].buffer, bytes);
      }
      scuBufferRemoveReference(op->argument[0].buffer);
      scuBufferFinalize(op->argument[1].buffer);
      break;
    default:
      ilpCustomOperationEnqueue(op);
      ilpMergedOperationEnqueue(op);
  }
}

void ilpWriteResult(ilp_op_t *op, int id, int type, char *data)
{
  switch (type)
  {
    case SC_VAR_INTEGER:
      op->argument[id].data.d = *((int*)data);
      break;
    case SC_VAR_DOUBLE:
      op->argument[id].data.f = *((double*)data);
      break;
  }   
}
